package com.nantian.nfcm.bms.report.web;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.text.DecimalFormat;
import java.util.List;

public class ReportController {
    /**
     * 文件下载
     *
     * @param file
     * @param request
     * @param response
     * @throws Exception
     */
    protected void downloadFile(File file, HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 因为本action没有经过filter，所以需手动转码
        String agent = request.getHeader("USER-AGENT");
        String filename = file.getName();
        if (agent != null && agent.contains("MSIE")) {
            filename = java.net.URLEncoder.encode(filename, "UTF-8");
        } else if (agent != null && agent.contains("Mozilla")) {
            filename = new String(filename.getBytes("UTF-8"), "ISO-8859-1");
        }

        response.reset();
        response.setContentType("application/vnd.ms-excel");
        response.setHeader("Content-disposition", "attachment;filename=" + filename);

        RandomAccessFile raf = null;
        FileChannel fcin = null;
        OutputStream out = null;
        WritableByteChannel cout = null;
        try {
            raf = new RandomAccessFile(file, "r");
            fcin = (raf.getChannel());

            out = response.getOutputStream();
            cout = Channels.newChannel(out);

            ByteBuffer bbuf = ByteBuffer.allocateDirect(10240);

            while (true) {
                bbuf.clear();
                if (fcin.read(bbuf) == -1) {
                    break;
                }
                bbuf.flip();
                cout.write(bbuf);
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (fcin != null) {
                fcin.close();
            }
            if (raf != null) {
                raf.close();
            }
            if (cout != null) {
                cout.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }

    /**
     * 合并单元格后补全边框
     *
     * @param sheet
     * @param region
     * @param cs
     */
    protected void setRegionStyle(Sheet sheet, CellRangeAddress region,
                                  CellStyle cs) {

        for (int i = region.getFirstRow(); i <= region.getLastRow(); i++) {

            Row row = sheet.getRow(i);
            if (row == null)
                row = sheet.createRow(i);
            for (int j = region.getFirstColumn(); j <= region.getLastColumn(); j++) {
                Cell cell = row.getCell(j);
                if (cell == null) {
                    cell = row.createCell(j);
                    cell.setCellValue("");
                }
                cell.setCellStyle(cs);

            }
        }
    }

    /**
     * 设置标题风格
     *
     * @param workbook
     * @return
     */
    protected CellStyle getTittleCellStyle(Workbook workbook) {
        CellStyle cellTittleStyle = workbook.createCellStyle();
        cellTittleStyle.setFillForegroundColor((short) 55);//HSSFColor.GREY_40_PERCENT.index);// 设置背景色
        cellTittleStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
        cellTittleStyle.setAlignment(CellStyle.ALIGN_CENTER); // 居中
        Font tittleFont = workbook.createFont();
        tittleFont.setFontHeightInPoints((short) 26);//设置字体大小
        cellTittleStyle.setFont(tittleFont);
        return cellTittleStyle;
    }

    /**
     * 设置列名风格
     *
     * @param workbook
     * @return
     */
    protected CellStyle getHeaderCellStyle(Workbook workbook) {
        CellStyle cellHeaderStyle = workbook.createCellStyle();
        cellHeaderStyle.setFillForegroundColor((short) 22);//HSSFColor.GREY_25_PERCENT.index);// 设置背景色
        cellHeaderStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);
        cellHeaderStyle.setAlignment(CellStyle.ALIGN_CENTER); // 居中
        cellHeaderStyle.setBorderBottom((short) 1); //下边框
        cellHeaderStyle.setBorderLeft((short) 1);//左边框
        cellHeaderStyle.setBorderTop((short) 1);//上边框
        cellHeaderStyle.setBorderRight((short) 1);//右边框
        Font headerFont = workbook.createFont();
        headerFont.setFontHeightInPoints((short) 10);//设置字体大小
        cellHeaderStyle.setFont(headerFont);
        return cellHeaderStyle;
    }

    /**
     * 设置内容风格
     *
     * @param workbook
     * @return
     */
    protected CellStyle getContextCellStyle(Workbook workbook) {
        CellStyle cellContextStyle = workbook.createCellStyle();
        cellContextStyle.setAlignment(CellStyle.ALIGN_CENTER); // 居中
        cellContextStyle.setBorderBottom((short) 1); //下边框
        cellContextStyle.setBorderLeft((short) 1);//左边框
        cellContextStyle.setBorderTop((short) 1);//上边框
        cellContextStyle.setBorderRight((short) 1);//右边框
        Font contextFont = workbook.createFont();
        contextFont.setFontHeightInPoints((short) 10);//设置字体大小
        cellContextStyle.setFont(contextFont);
        return cellContextStyle;
    }

    /**
     * 设置其它风格
     *
     * @param workbook
     * @return
     */
    protected CellStyle getOtherCellStyle(Workbook workbook) {
        CellStyle cellTimeStyle = workbook.createCellStyle();
        cellTimeStyle.setAlignment(CellStyle.ALIGN_RIGHT); // 靠右
        Font timeFont = workbook.createFont();
        timeFont.setFontHeightInPoints((short) 10);//设置字体大小
        cellTimeStyle.setFont(timeFont);
        return cellTimeStyle;
    }

    /**
     * 生成标题
     *
     * @param workbook 工作簿
     * @param sheet    表单
     * @param title    标题
     * @param firstRow 起始行数
     * @param rowCount 需要合并的行数
     * @param firstCol 起始列数
     * @param colCount 需要合并的列数
     * @return int nextRow 下一行的起始数
     */
    protected int createTitle(Workbook workbook, Sheet sheet, String title, int firstRow, int rowCount, int firstCol, int colCount) {
        //设置TITTLE风格
        CellStyle cellTittleStyle = getTittleCellStyle(workbook);
        Row row = sheet.createRow(firstRow);
        Cell cell = row.createCell(firstCol);
        cell.setCellValue(title);
        cell.setCellStyle(cellTittleStyle);
        sheet.addMergedRegion(new CellRangeAddress(firstRow, rowCount, firstCol, colCount >= 2 ? colCount : 0));
        return rowCount + 1;
    }

    /**
     * 生成操作人员及时间
     *
     * @param workbook  工作簿
     * @param sheet     表单
     * @param cellValue 表格内容
     * @param firstRow  起始行数
     * @param rowCount  需要合并的行数
     * @param firstCol  起始列数
     * @param colCount  需要合并的列数
     * @return int nextRow 下一行的起始数
     */
    protected int createOperater(Workbook workbook, Sheet sheet, String cellValue, int firstRow, int rowCount, int firstCol, int colCount) {
        CellStyle otherCellStyle = getOtherCellStyle(workbook);
        Row row = sheet.createRow(firstRow);
        Cell cell = row.createCell(firstCol);
        cell.setCellValue(cellValue);
        cell.setCellStyle(otherCellStyle);
        sheet.addMergedRegion(new CellRangeAddress(firstRow, rowCount, firstCol, colCount >= 2 ? colCount : 0));
        return firstRow + rowCount + 1;
    }

    /**
     * 生成表头
     *
     * @param workbook    工作簿
     * @param sheet       表单
     * @param headerNames 表头内容
     * @param firstRow    起始行数
     * @param rowCount    需要合并的行数
     * @param firstCol    起始列数
     * @return int nextRow 下一行的起始数
     */
    protected int createHeader(Workbook workbook, Sheet sheet, String[] headerNames, int firstRow, int rowCount, int firstCol) {
        CellStyle cellHeaderStyle = getHeaderCellStyle(workbook);
        Row row = sheet.createRow(firstRow);
        Cell cell = row.createCell(firstCol);
        cell.setCellValue("序号");
        cell.setCellStyle(cellHeaderStyle);

        int cellNum = 1;
        for(String headerName:headerNames){
            sheet.autoSizeColumn(cellNum, true);
            cell = row.createCell(cellNum);
            cell.setCellValue(headerName);
            cell.setCellStyle(cellHeaderStyle);
            cellNum++;
        }
        return firstRow + rowCount + 1;
    }

    /**
     * 生成无数据内容
     *
     * @param workbook    工作簿
     * @param sheet       表单
     * @param firstRow    起始行数
     * @param rowCount    需要合并的行数
     * @param firstCol    起始列数
     * @return int nextRow 下一行的起始数
     */
    protected int createNull(Workbook workbook, Sheet sheet, int firstRow, int rowCount, int firstCol, int colCount) {
        CellStyle cellContextStyle = getContextCellStyle(workbook);
        Row row = sheet.createRow(firstRow);
        Cell cell = row.createCell(firstCol);
        cell.setCellValue("无报表数据");
        cell.setCellStyle(cellContextStyle);
        sheet.addMergedRegion(new CellRangeAddress(firstRow, rowCount, firstCol, colCount >= 2 ? colCount : 0));
        return firstRow + rowCount + 1;
    }

    /**
     * 填充内容
     *
     * @param workbook      工作簿
     * @param sheet         表单
     * @param headerColumns 表头对象名称
     * @param firstRow      起始行
     * @param firstCol      起始列
     * @param datas         填充数据
     * @return int nextRow 下一行的起始数
     */
    protected int wirteExcel(Workbook workbook, Sheet sheet, String[] headerColumns, int firstRow, int firstCol, List<?> datas) {
        CellStyle cellContextStyle = getContextCellStyle(workbook);
        for (Object obj : datas) {
            Class clazz = obj.getClass();
            Row row = sheet.createRow(firstRow);
            //填入序号，序号取值为起始行减去3
            Cell cellIndex = row.createCell(0);
            cellIndex.setCellStyle(cellContextStyle);
            cellIndex.setCellValue(firstRow - 2);
            //填入序号后，数据填入从1开始
            int index = 1;
            for(String header:headerColumns){
                if(header.equals("NULL")){
                    Cell cell = row.createCell(index);
                    cell.setCellStyle(cellContextStyle);
                }
                else{
                    //首字母大写
                    String UHeader = Character.toUpperCase(header.charAt(0)) + header.substring(1, header.length());
                    String methodName = "get" + UHeader;
                    try {
                        // 设置要执行的方法
                        Method method = clazz.getDeclaredMethod(methodName);
                        //获取返回类型
                        String returnType = method.getReturnType().getName();
                        String data = method.invoke(obj) == null ? "" : method.invoke(obj).toString();

                        Cell cell = row.createCell(index);
                        cell.setCellStyle(cellContextStyle);
                        if (data != null && !"".equals(data)) {
                            if ("int".equals(returnType)) {
                                cell.setCellValue(Integer.parseInt(data));
                            } else if ("long".equals(returnType)) {
                                cell.setCellValue(Long.parseLong(data));
                            } else if ("float".equals(returnType)) {
                                cell.setCellValue(new DecimalFormat(".00").format(Float.parseFloat(data)));
                            } else if ("double".equals(returnType)) {
                                cell.setCellValue(new DecimalFormat(".00").format(Double.parseDouble(data)));
                            } else {
                                cell.setCellValue(data);
                            }
                        }
                    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
                index++;
            }
            firstRow++;
        }
        return firstRow + 1;
    }
}
